package de.koller.aframe.util.noise.n3D;

import de.koller.aframe.util.math.IFunction3D;
import de.koller.aframe.util.misc.BufferedRandomFloat3D;
import java.util.LinkedList;

public class ScrollingPerlin3D implements IFunction3D {
	
	private LinkedList<Perlin3DOctTree> perlins = new LinkedList<>();
	private float maxHeight = 1f;
	public int maxBuffered = 10;
	
	private final BufferedRandomFloat3D crnd;
	private int steps;
	private float persistence;
	
	public ScrollingPerlin3D( BufferedRandomFloat3D crnd, int steps, float persistence ) {
		this.crnd = crnd;
		this.steps = steps;
		this.persistence = persistence;
	}

	@Override
	public float getValue( float x, float y, float z ) {
		if( x >= 1 ) x = 0.9999f;
		if( y >= 1 ) y = 0.9999f;
		if( y >= 1 ) z = 0.9999f;
		if( x < 0 ) x = 0;
		if( y < 0 ) y = 0;
		if( z < 0 ) z = 0;
		
		int vx = (int)Math.floor( x );
		int vy = (int)Math.floor( y );
		int vz = (int)Math.floor( z );
		float dx = x - vx;
		float dy = y - vy;
		float dz = z - vz;
		
		return createPerlin( vx, vy, vz ).getValue( dx, dy, dz ) * ( 1f / maxHeight );
	}
	
	public void normalizeMaxBound( float maxHeight ) {
		this.maxHeight = maxHeight;
	}
	
	private synchronized Perlin3DOctTree createPerlin( int x, int y, int z ) {
		for( Perlin3DOctTree p : perlins )
			if( p.posY == y && p.posX == x && p.posZ == z )
				return p;
		
		System.out.println( "creating perlin: " + x + " / " + y + " / " + z );
		Perlin3DOctTree cp = Perlin3DOctTree.create( crnd, x, y, z, persistence, steps );
		//@todo better buffering
		perlins.addFirst( cp );
		while( perlins.size() > maxBuffered )
			perlins.removeLast();
		
		return cp;
	}
	
}
